package nimy.info.android.dinnertime.connectivity;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;

import nimy.info.android.dinnertime.HomeActivity;
import nimy.info.android.dinnertime.exception.ApplicationException;
import nimy.info.android.dinnertime.exception.ExceptionHandler;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import android.content.Context;
import android.os.Build;
import android.util.Log;

/**
 * For more information, please refer to <a href=
 * "http://android-developers.blogspot.com/2011/09/androids-http-clients.html"
 * >Http Client In Android </a>
 * 
 * @author Administrator
 * 
 */
public class WebConnector<T> {
	private static final String TAG = WebConnector.class.getName();
	public static final int CONNECTION_READ_TIMEOUT_IN_SECOND = 5;
	private ResponseParser<T> parser;
	private ResponseObject responseObject;

	private WebConnector(ResponseObject responseObject) {
		super();
		this.responseObject = responseObject;
	}

	/**
	 * Apache HTTP client has fewer bugs on Eclair and Froyo. It is the best
	 * choice for these releases.
	 * 
	 * @param context
	 * @return
	 * @throws IOException
	 * @throws MalformedURLException
	 */
	@SuppressWarnings("deprecation")
	public static <T> WebConnector<T> getConnector(final Context context,
			final String uri, final ResponseParser<T> parser)
			throws ApplicationException {
		if (HomeActivity.DEBUG) {
			Log.d(TAG, "The build version is: " + Build.VERSION.SDK);
		}
		try {
			if (HomeActivity.DEBUG) {
				Log.d(TAG, "Get data from url: " + uri);
			}
			if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
				HttpGet request = new HttpGet(uri);
				// set timeout
				HttpParams httpParameters = new BasicHttpParams();
				// Set the timeout in milliseconds until a connection is
				// established.
				// The default value is zero, that means the timeout is not
				// used.
				int timeoutConnection = CONNECTION_READ_TIMEOUT_IN_SECOND * 1000;
				HttpConnectionParams.setConnectionTimeout(httpParameters,
						timeoutConnection);
				// Set the default socket timeout (SO_TIMEOUT)
				// in milliseconds which is the timeout for waiting for data.
				int timeoutSocket = CONNECTION_READ_TIMEOUT_IN_SECOND * 1000;
				HttpConnectionParams
						.setSoTimeout(httpParameters, timeoutSocket);
				HttpClient client = new DefaultHttpClient(httpParameters);
				HttpResponse response = client.execute(request);
				WebConnector<T> buildFromHttpClient = buildFromHttpClient(response);
				buildFromHttpClient.setParser(parser);
				return buildFromHttpClient;
			} else {
				WebConnector<T> buildFromUrlConnection = buildFromUrlConnection(httpUrlConnection(uri));
				buildFromUrlConnection.setParser(parser);
				return buildFromUrlConnection;
			}
		} catch (Exception e) {
			String message = "Build URL failed with url: " + uri;
			ExceptionHandler.justLog(WebConnector.class, e, message);
			throw new ApplicationException(message, e);
		}
	}

	private static <T> WebConnector<T> buildFromHttpClient(HttpResponse response)
			throws IllegalStateException, IOException {
		int statusCode = response.getStatusLine().getStatusCode();
		InputStream content = response.getEntity().getContent();
		ResponseObject ro = ResponseObject.from(statusCode, content);
		return new WebConnector<T>(ro);
	}

	private static HttpURLConnection httpUrlConnection(final String uri)
			throws IOException, MalformedURLException {
		HttpURLConnection httpURLConnection = (HttpURLConnection) (URI.create(
				uri).toURL().openConnection());
		httpURLConnection
				.setConnectTimeout(CONNECTION_READ_TIMEOUT_IN_SECOND * 1000);
		httpURLConnection
				.setReadTimeout(CONNECTION_READ_TIMEOUT_IN_SECOND * 1000);
		return httpURLConnection;
	}

	private static <T> WebConnector<T> buildFromUrlConnection(
			HttpURLConnection connection) throws IOException {

		return new WebConnector<T>(ResponseObject.from(
				connection.getResponseCode(), connection.getInputStream()));
	}

	public ResponseParser<T> getParser() {
		return parser;
	}

	public void setParser(ResponseParser<T> parser) {
		this.parser = parser;
	}

	public ResponseObject getResponseObject() {
		return responseObject;
	}

	public T parseResponseTo() throws ApplicationException {
		if (getParser() != null) {
			return getParser().parse(getResponseObject());
		}
		return null;
	}
}
